package com.yc.mybatis.core;

import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;
import java.util.Vector;

import com.mysql.jdbc.DatabaseMetaData;

/**
 * 数据库连接池
 * @author 27594
 *
 */
public class ConnectionPool {
	private String driverClassName = "com.mysql.jdbc.Driver";
	private String url = "jdbc:mysql://127.0.0.1:3306/yc_103_5_snacknet";
	private String username = "root";
	private String password = "a";

	private int initConnections = 10;
	private int incrementConnections = 5;
	private int maxConnections = 50;
	private Vector<PooledConnection> connections = null;

	public ConnectionPool() {
		super();
	}

	public ConnectionPool(String driverClassName, String url, String username, String password) {
		this.driverClassName = driverClassName;
		this.url = url;
		this.username = username;
		this.password = password;
	}

	public int getInitConnections() {
		return initConnections;
	}

	public void setInitConnections(int initConnections) {
		this.initConnections = initConnections;
	}

	public int getIncrementConnections() {
		return incrementConnections;
	}

	public void setIncrementConnections(int incrementConnections) {
		this.incrementConnections = incrementConnections;
	}

	public int getMaxConnections() {
		return maxConnections;
	}

	public void setMaxConnections(int maxConnections) {
		this.maxConnections = maxConnections;
	}

	public Vector<PooledConnection> getConnections() {
		return connections;
	}

	public void setConnections(Vector<PooledConnection> connections) {
		this.connections = connections;
	}

	/**
	 * 返回当前连接池中可用的连接数
	 * @return
	 */
	public int getActiveConnection() {
		return this.connections.size();
	}

	/**
	 * 创建连接池
	 * @throws Exception 
	 */
	public synchronized void createPool() throws Exception {
		if(connections != null) { //说明已经创建
			return;
		}

		Driver driver = (Driver) Class.forName(this.driverClassName).newInstance();
		DriverManager.registerDriver(driver);

		connections = new Vector<PooledConnection>();
		createConnections(this.initConnections); //创建连接池
	}

	/**
	 * 创建指定数量的连接
	 * @param initConnections2
	 * @throws SQLException 
	 */
	private void createConnections(int numConnections) throws SQLException {
		//循环创建
		for(int i = 0; i < numConnections; i ++) {
			if(this.maxConnections > 0 && this.connections.size() >= this.maxConnections) {//说明连接池已经满了
				return;
			}

			//创建连接到连接池中
			try {
				connections.addElement(new PooledConnection(newConnection(), i));
			} catch (Exception e) {
				System.out.println("数据库连接池创建失败...");
				e.printStackTrace();
				throw new SQLException();
			}
		}
	}

	/**
	 * 创建连接的方法
	 * @return
	 * @throws SQLException
	 */
	private Connection newConnection() throws SQLException {
		Connection con = DriverManager.getConnection(url,username, password);
		if(connections.size() == 0) { //说明是第一个连接
			DatabaseMetaData metaData = (DatabaseMetaData) con.getMetaData();
			int driverMaxConnection = metaData.getMaxConnections(); //获取数据库能支持的最大连接数
			if(driverMaxConnection > 0 && driverMaxConnection < this.maxConnections) { //说明用户的最大连接数太大
				this.maxConnections = driverMaxConnection;

			}
		}
		return con;
	}

	/**
	 * 获取连接的方法
	 * @author 27594
	 * @throws InterruptedException 
	 * @throws SQLException 
	 */
	public synchronized Connection getConnection() throws InterruptedException, SQLException {
		if(connections == null || connections.isEmpty()) {
			return null;
		}
		Connection con = getFreeConnection(); //获取一个空闲的连接
		while(con == null) { //说明没有获取到连接
			wait(500); //等待500毫秒之后再次获取
			con = getConnection();
		}
		return con;
	}


	/**
	 * 获取空闲连接的方法
	 * @return
	 * @throws SQLException 
	 */
	private Connection getFreeConnection() throws SQLException {
		Connection con = findFreeConnection(); //查询空闲连接的方法
		if(con == null) { //说明没有找到空闲的连接
			createConnections(incrementConnections); //扩容
			con = findFreeConnection(); //扩容之后再找
			if(con == null) { //如果还是空
				return null;
			}
		}
		return con;
	}

	/**
	 * 查找空闲连接的方法
	 * @return
	 */
	private Connection findFreeConnection() {
		Connection con = null;
		PooledConnection poolCon = null;

		Enumeration<PooledConnection> enumerate = connections.elements();
		while(enumerate.hasMoreElements()) {
			poolCon = enumerate.nextElement(); //获取下一个连接对象
			if(!poolCon.isBusy()) { //说明是空闲连接
				con = poolCon.getConnection(); //获取这个连接
				poolCon.setBusy(true); //设置为忙碌状态

				if(!testConnection(con)) { //测试连接是否可用
					try {
						con = newConnection(); //如果这个链接不可用，那就换一个
					} catch (SQLException e) {
						e.printStackTrace();
					}
					poolCon.setConnection(con);
				}
				System.out.println(poolCon.getPid() + "号连接------为您服务");
				break;
			}
		}

		return con;
	}

	/**
	 * 测试连接的方法
	 * @param con
	 * @return
	 */
	private boolean testConnection(Connection con) {
		try {
			con.setAutoCommit(true);
		} catch (SQLException e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}

	/**
	 * 关闭连接池的方法
	 * @throws InterruptedException 
	 */
	public synchronized void closeConnectionPool() throws InterruptedException {
		if(connections == null || connections.isEmpty()) {
			return;
		}
		
		PooledConnection poolcon = null;
		Enumeration<PooledConnection> enumerate = connections.elements();
		while(enumerate.hasMoreElements()) {
			poolcon = enumerate.nextElement();
			if(poolcon.isBusy()) { //说明这个连接正在用
				wait(500);
			}
			closeConnection(poolcon.getConnection());
			connections.removeElement(poolcon);
		}
				
	}


	/**
	 * 释放连接的方法
	 * @param connection
	 */
	public void freeConnection(Connection con) {
		if(con == null) {
			return;
		}
		PooledConnection poolCon = null;
		Enumeration<PooledConnection> enumerate = connections.elements();
		while(enumerate.hasMoreElements()) {
			poolCon = enumerate.nextElement();
			if(con == poolCon.getConnection()) {
				poolCon.setBusy(false);
				return;
			}
		}
		
	}

	/**
	 * 关闭连接的方法
	 * @param connection
	 */
	private void closeConnection(Connection con) {
		if(con != null) {
			try {
				con.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		
	}

	private void wait(int mseconds) {
		try {
			Thread.sleep(mseconds);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}


	class PooledConnection{
		private Connection connection = null; //数据库连接
		private boolean busy = false; //连接的状态
		private int pid; //连接的编号

		public PooledConnection() {
			super();
		}
		public PooledConnection(Connection connection, int pid) {
			super();
			this.connection = connection;
			this.pid = pid;
		}
		public Connection getConnection() {
			return connection;
		}
		public void setConnection(Connection connection) {
			this.connection = connection;
		}
		public boolean isBusy() {
			return busy;
		}
		public void setBusy(boolean busy) {
			this.busy = busy;
		}
		public int getPid() {
			return pid;
		}
		public void setPid(int pid) {
			this.pid = pid;
		}
	}

}
